﻿#region Copyright Statement
//  ------------------------------------------------------------------------------
//  
//    This file is part of The Streambolics Library.
//    Copyright © 2005-2009, Stephan Leclercq & Streambolics
//    All rights reserved.
//  
//    The Streambolics Library is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//  
//    The Streambolics Library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//  
//    You should have received a copy of the GNU General Public License
//    along with Streambolics; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//  
//  ------------------------------------------------------------------------------
#endregion

using System;
using System.Collections.Generic;
using System.Text;

namespace Streambolics
{
    /// <summary>
    ///     The equivalent of StringBuilder for byte messages.
    /// </summary>

    public class MessageBuilder
    {
        //  TODO : Make this an IMessageProducer
        //  TODO : Make this an IMessageConsumer

        private byte[] _Buffer;
        private int _Capacity;
        private int _Count;

        /// <summary>
        ///     Create a MessageBuilder with the given initial capacity.
        /// </summary>
        /// <param name="aCapacity">
        ///     The initial capacity.
        /// </param>
        /// <remarks><para>
        ///     The capacity of the MessageBuilder will expand as needed.
        /// </para></remarks>

        public MessageBuilder (int aCapacity)
        {
            _Capacity = System.Math.Max (aCapacity, 32);
            _Count = 0;
            _Buffer = new byte[_Capacity];
        }

        /// <summary>
        ///     Create a MessageBuilder with a default capacity.
        /// </summary>

        public MessageBuilder ()
            : this (128)
        {
        }

        private void Resize (int aNewSize)
        {
            if (aNewSize > _Capacity)
            {
                _Capacity += _Capacity / 2;
                if (aNewSize > _Capacity)
                {
                    _Capacity = aNewSize;
                }
                _Buffer = _Buffer.Resize (_Capacity);
            }

        }

        /// <summary>
        ///     Append a single byte at the end of the message.
        /// </summary>
        /// <param name="b">
        ///     The byte to append.
        /// </param>

        public void Append (byte b)
        {
            if (_Count >= _Capacity)
            {
                Resize (_Count + 1);
            }
            _Buffer[_Count++] = b;
        }

        /// <summary>
        ///     Append bytes at the end of the message.
        /// </summary>
        /// <param name="b">
        ///     The bytes to append
        /// </param>

        public void Append (byte[] b)
        {
            int l = b.Length;
            Resize (_Count + l);
            // TODO : use Buffer.BlockCopy
            b.CopyTo (_Buffer, _Count);
            _Count += l;
        }

        /// <summary>
        ///     Reset the message to empty.
        /// </summary>
        /// <remarks><para>
        ///     Resetting the message will not free the space allocated
        ///     for the buffer, which will remain at the current capacity.
        /// </para></remarks>

        public void Reset ()
        {
            _Count = 0;
        }

        /// <summary>
        ///     The value of a byte anywhere in the message.
        /// </summary>
        /// <param name="aPos">
        ///     The position within the message. The first character
        ///     is at position 0, the last at position Length-1.
        /// </param>
        /// <returns>
        ///     The character at the given position.
        /// </returns>

        public byte this[int aPos]
        {
            get
            {
                return _Buffer[aPos];
            }
        }

        /// <summary>
        ///     A representation of the message.
        /// </summary>
        /// <returns>
        ///     An array of bytes representing the currently
        ///     built message.
        /// </returns>
        /// <remarks><para>
        ///     Each call to this function will return a newly allocated
        ///     array of bytes, so each array is independant of the others.
        /// </para></remarks>

        public byte[] ToBytes ()
        {
            return _Buffer.Resize (_Count);
        }

        /// <summary>
        ///     The size of the current message
        /// </summary>

        public int Length
        {
            get
            {
                return _Count;
            }
        }

    }
}
